package com.travel.sight.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.travel.common.to.AttractionInfoTo;
import com.travel.common.to.UpdateUserAttractionWeightTo;
import com.travel.common.to.UpdateUserTagWeightTo;
import com.travel.common.to.UserBehaviorWeightTo;
import com.travel.common.utils.R;
import com.travel.sight.entity.AttractionInfoEntity;
import com.travel.sight.feign.RecommendFeignService;
import com.travel.sight.service.AttractionInfoService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.travel.common.utils.PageUtils;
import com.travel.common.utils.Query;

import com.travel.sight.dao.ClickDao;
import com.travel.sight.entity.ClickEntity;
import com.travel.sight.service.ClickService;

import javax.xml.crypto.Data;


@Service("clickService")
public class ClickServiceImpl extends ServiceImpl<ClickDao, ClickEntity> implements ClickService {

    @Autowired
    StringRedisTemplate redisTemplate;

    @Autowired
    AttractionInfoService attractionInfoService;

    @Autowired
    RecommendFeignService recommendFeignService;


    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<ClickEntity> page = this.page(
                new Query<ClickEntity>().getPage(params),
                new QueryWrapper<ClickEntity>()
        );

        return new PageUtils(page);
    }

    /**
     * 1. 修改点击数
     * 2. mysql中添加点击操作
     * 3. 更新景点score
     * 4. 更新用户对该景点的权重
     * 5. 更新用户对景点标签的权重
     * @param attractionId
     * @param userId
     */
    @Override
    public void updateAfterClick(Integer attractionId, Integer userId) {
        UserBehaviorWeightTo weight = recommendFeignService.getUserBehaviorWeight();
        Double clickWeight = weight.getClicksWeight();

        //1. 修改点击数 +1
        String key = "attraction_info:"+attractionId+":click_num";
        redisTemplate.opsForValue().increment(key);

        //2. mysql中添加点击操作
        // 先判断是否点击过
        ClickEntity entity = this.baseMapper.selectOne(new QueryWrapper<ClickEntity>().eq("user_id", userId).eq("attraction_id", attractionId));
        if(entity == null){
            // 没点击过，新增
            ClickEntity clickEntity = new ClickEntity();
            clickEntity.setAttractionId(attractionId);
            clickEntity.setUserId(userId);
            clickEntity.setClick(1);
            clickEntity.setAddTime(new Date());
            clickEntity.setUpdateTime(new Date());
            this.baseMapper.insert(clickEntity);
        }else{
            // 点击过，次数+1
            Integer clickNum = entity.getClick();
            entity.setClick(clickNum+1);
            this.baseMapper.updateById(entity);
        }

        //3. 更新景点score
        //评分计算公式：(点击数/最大点击数 × 0.1 + 点赞数/最大点赞数 × 0.3 + 收藏数/最大收藏数 × 0.3 + 评论数/最大评论数 ×0.3 ) ×100
        //3.1 从redis中获取 最大点击数、最大点赞数、最大收藏数、最大评论数
        String maxClickKey = "max_value:click_num";
        String maxLikeKey = "max_value:like_num";
        String maxCollectionKey = "max_value:collection_num";
        String maxCommentKey = "max_value:comment_num";

        Integer maxClick = Integer.valueOf(redisTemplate.opsForValue().get(maxClickKey));
        Integer maxLike = Integer.valueOf(redisTemplate.opsForValue().get(maxLikeKey));
        Integer maxCollection = Integer.valueOf(redisTemplate.opsForValue().get(maxCollectionKey));
        Integer maxComment = Integer.valueOf(redisTemplate.opsForValue().get(maxCommentKey));

        //3.2 获取当前景点的 点击数、点赞数、收藏数、评论数（从redis获取，最新的）
        String clickKey = "attraction_info:"+attractionId+":click_num";
        String likeKey = "attraction_info:"+attractionId+":like_num";
        String collectionKey = "attraction_info:"+attractionId+":collection_num";
        String commentKey = "attraction_info:"+attractionId+":comment_num";

        Integer clickNum = Integer.valueOf(redisTemplate.opsForValue().get(clickKey));
        Integer likeNum = Integer.valueOf(redisTemplate.opsForValue().get(likeKey));
        Integer collectionNum = Integer.valueOf(redisTemplate.opsForValue().get(collectionKey));
        Integer commentNum = Integer.valueOf(redisTemplate.opsForValue().get(commentKey));

        //3.3 计算并更新score（redis）
        // 计算新的score值
        Double newScore = (clickNum.doubleValue() / maxClick.doubleValue() * 0.1 + likeNum.doubleValue() / maxLike.doubleValue() * 0.3 +
                collectionNum.doubleValue() / maxCollection.doubleValue() * 0.3 + commentNum.doubleValue() / maxComment.doubleValue() * 0.3) * 100;
        System.out.println("计算得到新的score为 "+newScore);

        String scoreKey = "attraction_info:"+attractionId+":score";
        redisTemplate.opsForValue().set(scoreKey,String.valueOf(newScore));

        //4. 更新用户对该景点的权重
        AttractionInfoEntity byId = attractionInfoService.getById(attractionId);

        UpdateUserAttractionWeightTo attractionWeightTo = new UpdateUserAttractionWeightTo();
        attractionWeightTo.setAttractionId(byId.getAttractionId());
        attractionWeightTo.setName(byId.getName());
        attractionWeightTo.setTag(byId.getTag());
        attractionWeightTo.setWeight(clickWeight);

        R r1 = recommendFeignService.updateUserAttractionWeight(attractionWeightTo,userId);
        if(r1.getCode() == 0){
            System.out.println("更新用户对该景点的权重 成功");
        }else{
            System.out.println("更新用户对该景点的权重 失败");
        }

        //5. 更新用户对景点标签的权重
        UpdateUserTagWeightTo tagWeightTo = new UpdateUserTagWeightTo();
        tagWeightTo.setTagName(byId.getTag());
        tagWeightTo.setWeight(clickWeight);

        R r2 = recommendFeignService.updateUserTagWeight(tagWeightTo,userId);
        if(r2.getCode() == 0){
            System.out.println("更新用户对景点标签的权重 成功");
        }else{
            System.out.println("更新用户对景点标签的权重 失败");
        }
    }

}